package com.dongpl.aspect;

import com.alibaba.fastjson.JSON;
import com.dongpl.annotation.MyLog;
import com.dongpl.module.sysLog.entity.SysLog;
import com.dongpl.module.sysLog.service.SysLogService;
import com.dongpl.utils.HttpContextUtils;
import com.dongpl.utils.IPUtils;
import com.dongpl.utils.ShiroUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Date;

/**
 * 日志加载切面
 * @author Administrator
 */
@Aspect
@Component
public class SysLogAspect {

    @Resource
    private SysLogService sysLogService;

    /**
     * 定义切点 @Pointcut
     * 在注解的位置切入代码
     */
//    @Pointcut("@annotation( com.dongpl.annotation.MyLog)")
    @Pointcut("execution(public * com.dongpl.module.*.controller..*.*(..))")
    public void logPointCut() {
    }

    /**
     * 切面 配置通知
     */
    @AfterReturning("logPointCut()")
    public void saveSysLog(JoinPoint joinPoint) {
        //保存日志
        SysLog sysLog = new SysLog();
        //从切面织入点处通过反射机制获取织入点处的方法
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        //获取切入点所在的方法
        Method method = signature.getMethod();
        //获取操作
        MyLog myLog = method.getAnnotation(MyLog.class);
        String value;
        if (myLog != null) {
            value = myLog.value();
        } else {
            value = "一次性请求操作";
        }
        //保存获取的操作
        sysLog.setOperation(value);
        //获取请求的类名
        String className = joinPoint.getTarget().getClass().getName();
        //获取请求的方法名
        String methodName = method.getName();
        sysLog.setMethod(className + "." + methodName);
        //请求的参数
        Object[] args = joinPoint.getArgs();
        //将参数所在的数组转换成json
//        String params = JSON.toJSONString(args);
        Object[] arguments  = new Object[args.length];
        for (int i = 0; i < args.length; i++) {
            if (args[i] instanceof ServletRequest || args[i] instanceof ServletResponse || args[i] instanceof MultipartFile) {
                //ServletRequest不能序列化，从入参里排除，否则报异常：java.lang.IllegalStateException: It is illegal to call this method if the current request is not in asynchronous mode (i.e. isAsyncStarted() returns false)
                //ServletResponse不能序列化 从入参里排除，否则报异常：java.lang.IllegalStateException: getOutputStream() has already been called for this response
                continue;
            }
            arguments[i] = args[i];
        }
        String params;
        try {
            params = JSON.toJSONString(arguments);
        } catch (Exception e) {
            params = Arrays.toString(arguments);
        }
        sysLog.setParams(params);
        //获取用户名
        String username = "";
        if (ShiroUtils.isLogin()){
            username = ShiroUtils.getLoginUser().getUsername();
        }
        sysLog.setUsername(username);
        //获取用户ip地址
        HttpServletRequest request = HttpContextUtils.getHttpServletRequest();
        sysLog.setIp(IPUtils.getIpAddr(request));
        sysLog.setCreateDate(new Date());
        //调用service保存SysLog实体类到数据库
        sysLogService.save(sysLog);
    }
}
